<?php

namespace App\Services\Cart;
use App\Exceptions\BusinessException;
use App\Common\ResponseCode;
use App\Models\Cart\CartItem;
use App\Models\Cart\Carts;
use App\Models\Goods\Goods;
use App\Models\Goods\Products;
use App\Params\H5\CartAddParams;
use App\Params\H5\CartCheckoutParams;
use App\Params\H5\CartUpdateParams;
use App\Repository\AddressRepository;
use App\Repository\CartRepository;
use App\Repository\CouponRepository;
use App\Repository\CustomerCouponRepository;
use App\Services\BaseService;
use App\Services\Customer\AddressService;
use App\Services\Customer\CustomerService;
use App\Services\Promotion\CouponService;
use App\Traits\Calculator;
use App\Traits\DateTimeTrait;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * 购物车相关业务类
 *
 * @author WangBin
 * @date 2021-09-24
 * @package App\Http\Services\Cart
 */
class CartsService extends BaseService
{
    use Calculator, DateTimeTrait;

    /**
     * 删除购物车商品
     *
     * @param array $productIds
     * @param int $customerId
     * @return mixed
     */
    public function delete(array $productIds, int $customerId)
    {
        $cart = CartRepository::getInstance()->getByCustomerId($customerId);
        CartRepository::getInstance()->delete($cart->cart_id, $productIds);
        $this->recount($cart->cart_id);
        return true;
    }

    /**
     * 加入购物车
     *
     * @param CartAddParams $params
     * @return mixed
     * @throws BusinessException
     */
    public function add(CartAddParams $params)
    {
        try {
            DB::beginTransaction();
            // 获取客户的购物车
            $cart = $this->getCustomerCart($params->getCustomerId(), 0);
            // 检查商品是否已在购物车，存在则累加数量
            $cartItem = CartItem::checkItem($cart->cart_id, $params->getProductId());
            // 获取货品信息
            $goods = Goods::getById($params->getGoodsId());
            // 获取商品信息
            $product = Products::getById($params->getProductId(), true);
            // 检查是否需要校验库存
            if($goods->stock_manage && $product->stock_qty < $params->getQty()) {
                throw new \Exception("商品：{$goods->name} 库存不足！");
            }

            if(is_null($cartItem)) {
                $cartItem = new CartItem();
                $cartItem->goods_id = $params->getGoodsId();
                $cartItem->cart_id = $cart->cart_id;
                $cartItem->name = $goods->name;
                $cartItem->qty_ordered = $params->getQty();
                $cartItem->product_id = $params->getProductId();
                $cartItem->goods_bn = $goods->goods_bn;
                $cartItem->price = $product->sales_price;
                $cartItem->unit = $goods->unit;
                $cartItem->weight = $goods->weight;
                $cartItem->specs = $product->specs;
                $cartItem->is_selected = 1;
                $cartItem->total_amount = $product->sales_price * $params->getQty();
                $cartItem->image_url = $product->image_url;
            } else {
                $cartItem->qty_ordered += $params->getQty();
                $cartItem->total_amount += $product->sales_price * $params->getQty();
            }

            if($cartItem->save()) {
                // 更新购物车数据
                if(!$this->recount($cart->cart_id)) {
                    throw new \Exception("更新购物车数据失败！");
                }
            }
            DB::commit();
            return Carts::getById($cart->cart_id)->total_qty;
        } catch (\Exception $exception) {
            DB::rollBack();
            Log::error('[加入购物车] 出错：' . $exception->getMessage());
            throw new BusinessException(ResponseCode::CART_SAVE_FAIL, ['error' => $exception->getMessage()]);
        }
    }

    /**
     * 获取客户购物车
     * 可获取加购购物车及快速购买购物车
     *
     * @param int $customerId
     * @param int $fastBuy
     * @return mixed
     */
    public function getCustomerCart(int $customerId, $fastBuy = 0)
    {
        $cart = Carts::getByCustomerId($customerId, 0);
        // 购物车不存在则创建空的购物车
        if(is_null($cart)) {
            $this->createEmptyCart($customerId);
            $cart = Carts::getByCustomerId($customerId, 0);
        }
        return $cart;
    }

    /**
     * 创建客户购物车
     * 1、加购购物车 2、立即购买购物车
     *
     * @param $customerId
     */
    private function createEmptyCart($customerId)
    {
        // 获取客户
        $customer = CustomerService::getInstance()->getById($customerId);
        foreach ([0, 1] as $value)
        {
            $cart = new Carts();
            $cart->customer_id = $customerId;
            $cart->customer_name = $customer->nickname;
            $cart->fast_buy = $value;
            $cart->save();
        }
    }

    /**
     * 获取购物车明细
     *
     * @param int $customerId
     * @param int $fastBuy
     * @return
     */
    public function getCartItems(int $customerId, int $fastBuy = 0)
    {
        // 获取购物车明细
        $result = ['total_qty' => 0, 'list' => []];
        $cart = CartRepository::getInstance()->getByCustomerId($customerId, 0);
        if(!is_null($cart)) {
            $list = CartRepository::getInstance()->getItemsByCustomerId($customerId, $fastBuy);
            $result['total_qty'] = $cart->total_qty;
            $result['list'] = $list;
        }
        return $result;
    }

    /**
     * 更新购物车
     *
     * @param CartUpdateParams $data
     * @return bool
     * @throws BusinessException
     */
    public function update(CartUpdateParams $data)
    {
        try {
            $cart = Carts::getByCustomerId($data->getCustomerId(), 0);
            $cartItem = CartItem::getByCartIdAndProductId($cart->cart_id, $data->getProductId());
            if(is_null($cartItem)) {
                throw new \Exception('获取明细出错！');
            }
            // 开启事务
            DB::beginTransaction();
            switch ($data->getAction())
            {
                case 'change':
                    // 更新购物车商品数量
                    $cartItem->qty_ordered = $data->getQty();
                    $cartItem->total_amount = $data->getQty() * $cartItem->price;
                    $cartItem->save();
                    break;
                case 'delete':
                    // 删除购物车商品
                    $cartItem->delete();
                    break;
                case 'checked':
                    // 选中/取消
                    $selected = $cartItem->is_selected ? 0 : 1;
                    $cartItem->is_selected = $selected;
                    $cartItem->save();
                    break;
            }
            DB::commit();
            // 重新计算购物车数据
            $this->recount($cart->cart_id);
            return Carts::getById($cart->cart_id)->total_qty;
        } catch (\Exception $exception) {
            Log::error('[更新购物车] 出错：' . $exception->getMessage());
            DB::rollBack();
            throw new BusinessException(ResponseCode::CART_UPDATE_FAIL, ['error' => $exception->getMessage()]);
        }
    }

    /**
     * 获取结算页数据
     *
     * @param int $customerId
     * @param int $fastBuy
     * @return array
     */
    public function checkout(CartCheckoutParams $params)
    {
        // 获取客户默认的收货地址
        $address = AddressRepository::getInstance()->getByCustomerId($params->getCustomerId(), 1);
        // 配送方式
        $expressType = 'EXPRESS';
        // 配送范围内
        $isIntraRegion = true;
        // 物流费用
        $expressAmount = 0;
        if(!is_null($address)) {
            // todo
        }
        // 结算商品数据统计
        $totalAmount = 0;
        $totalQty = 0;

        // 获取购物车选中商品
        $cartItems = CartItem::getItemsByCustomerId($params->getCustomerId(), 0, 1);
        $cartItems->each(function ($item) use (&$totalAmount, &$totalQty){
            $totalAmount = $this->addNum($item->total_amount, $totalAmount);
            $totalQty = $this->addNum($item->qty_ordered, $totalQty);
        });

        // 优惠券列表
        $filter = ['customer_id' => $params->getCustomerId(), 'type' => 'unused', 'status' => 1];
        $couponList = CouponRepository::getInstance()->getMyList($filter)->get();
        $couponList->each(function ($item) use ($totalAmount) {
            $item->start_at = $this->formatDateTime($item->start_at, 'Y-m-d');
            $item->end_at = $this->formatDateTime($item->end_at, 'Y-m-d');
            // 是否满足优惠策略
            $isApply = 0;
            if($this->compare($totalAmount, $item->amount) >= 0) {
                $isApply = 1;
            }
            $item->is_apply = $isApply;
        });
        // 根据订单金额获取最大的优惠券优惠金额和优惠券Id
        $couponDiscount = CouponService::getInstance()->getCouponDiscount($params->getCustomerId(), $totalAmount);
        // 选择优惠券，则更新优惠券为已选中状态、计算优惠金额
        if($params->getCustomerCouponId()) {
            CustomerCouponRepository::getInstance()->save(['is_selected' => 1], $params->getCustomerCouponId());
        }
        return [
            'goods_list' => $cartItems,
            'address' => $address,
            'express_amount' => $this->format($expressAmount),
            'express_type' => $expressType,
            'total_amount' => $totalAmount,
            'total_qty' => (int)$totalQty,
            'is_intra_region' => $isIntraRegion,
            'coupon_list' => $couponList,
            'coupon_discount' => $couponDiscount['coupon_discount'],
            'coupon_id' => $couponDiscount['coupon_id'],
            'pay_amount' => $this->sub($this->addNum($totalAmount, $expressAmount), $couponDiscount['coupon_discount'])
        ];
    }

    /**
     * 获取购物车收货地址
     *
     * @param int $customerId
     * @param int $fastBuy
     * @return array
     */
    public function getAddress(int $customerId, int $fastBuy = 0)
    {
        $result = [];
        // 获取客户购物车
        $cart = $this->getCustomerCart($customerId, $fastBuy);
        if(empty($cart->address_id)) return $result;
        $address = AddressService::getInstance()->get($cart->address_id);
        $result['id'] = $address->address_id;
        $result['is_default'] = $address->is_default;
        $result['phone'] = $address->phone;
        $result['address'] = $address->full_address;
        $result['consignee'] = $address->contact_name;
        return $result;
    }

    /**
     * 重新计算购物车
     *
     * @param int $cartId
     * @return int
     */
    private function recount(int $cartId)
    {
        // 获取购物车
        $cart = Carts::getById($cartId);
        // 获取购物车明细
        $cartItems = CartItem::getItems($cartId);
        $cart->total_qty = 0;
        $cart->total_amount = 0;
        foreach ($cartItems as $cartItem)
        {
            // 购物车总金额
            $cart->total_amount += $cartItem->total_amount;
            // 购物车总数量
            $cart->total_qty += $cartItem->qty_ordered;
        }
        $cart->total_count = $cartItems->count();
        return $cart->save();
    }

    /**
     * 获取购物车总数量
     *
     * @param int $customerId
     * @return int|mixed
     */
    public function getTotal(int $customerId)
    {
        $cart = Carts::getByCustomerId($customerId, 0);
        return is_null($cart) ? 0 : $cart->total_qty;
    }
}
